﻿using RuoVea.Entity;
using Mapster;
using SqlSugar;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using RuoVea.Autowired;
using RuoVea.ExSqlSugar;

using RuoVea.ExIdGen;
using System;
using RuoVea.ExEnum;
using RuoVea.ExUtil.Exceptions;
using RuoVea.ExUtil.EnumExtension;
using RuoVea.ExCrypt;
using RuoVea.Util;
using System.Linq.Expressions;

namespace RuoVea.Service
{
    /// <summary>
    /// 用户服务
    /// </summary>
    [AppService(ServiceLifetime.Transient)]
    public class SysUserService : ISysUserService
    {
        private readonly ISqlSugarRepository<SysUser> _sysUserRep;  // 用户表仓储 
        private readonly ISysCacheService _sysCacheService;
        private readonly ISysUserRoleService _sysUserRoleService;
        private readonly IUserManager _userManager;

        public SysUserService(ISqlSugarRepository<SysUser> sysUserRep,
         IUserManager userManager,
                              ISysUserRoleService sysUserRoleService,
                              ISysCacheService sysCacheService)
        {
            _sysUserRep = sysUserRep;
            _sysUserRoleService = sysUserRoleService;
            _userManager = userManager;
            _sysCacheService = sysCacheService;
        }

        /// <summary>
        /// 用户登录
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<SysUser> LoginAsync( LoginInput input)
        {
            // 获取加密后的密码
            var encryptPassword = RuoVea.ExCrypt.Md5Crypt.Encrypt(input.Password);

            // 判断用户名和密码是否正确(排除全局多租户过滤器)Filter(null,true)


            var user = await _sysUserRep.FirstOrDefaultAsync(u => u.Account.Equals(input.Account) && u.Password.Equals(encryptPassword) && u.IsDeleted == false);
                //.WhereIF(input.TenantId.HasValue && input.TenantId.Value > 0, m => m.TenantId == input.TenantId).FirstAsync(u =>
                //    u.Account.Equals(input.Account) && u.Password.Equals(encryptPassword) && u.Deleted == 0);

            return user;
        }

        /// <summary>
        /// 分页查询用户
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<dynamic> QueryUserPageList(   UserInput input)
        {
            var superAdmin = _userManager.SuperAdmin;
            var searchValue = input.SearchValue;

            var users = await _sysUserRep.Context.Queryable<SysUser>()
                .WhereIF(!string.IsNullOrWhiteSpace(searchValue), (u) => u.Account.Contains(input.SearchValue.Trim()) ||
                                                                            u.Name.Contains(input.SearchValue.Trim()) ||
                                                                            u.Phone.Contains(input.SearchValue.Trim()))
                .WhereIF(Enum.IsDefined(typeof(StatusEnum), input.SearchStatus), (u) => u.Status == input.SearchStatus)
                .WhereIF(!superAdmin, (u) => u.AdminType != AdminType.SuperAdmin)
                .Select<UserOutput>("u.*").ToPagedListAsync(input.PageNo, input.PageSize);

            return users.XnPagedResult();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<dynamic> List(UserInput input)
        {
            var superAdmin = _userManager.SuperAdmin;
            var searchValue = input.SearchValue;

            var roles = await _sysUserRep.Context.Queryable<SysRole>().OrderBy(r=>r.Sort).Select(r=>new RoleUser
            {
                RoleId=r.Id,
                RoleName=r.Name,
            }).ToListAsync();

            var users = await _sysUserRep.Context.Queryable<SysUser>()
                .InnerJoin<SysUserRole>((u, r) => u.Id == r.SysUserId )
                .InnerJoin<SysUserPos>((u,r,   sp)=>u.Id==sp.SysUserId)
                .InnerJoin<SysPos>((u, r,   sp, p)=>sp.SysPosId==p.Id)
                .Where(u =>u.AdminType== AdminType.None)
                .WhereIF(!string.IsNullOrWhiteSpace(searchValue), (u, r, sp, p) => u.Account.Contains(input.SearchValue.Trim()) || u.Name.Contains(input.SearchValue.Trim()) || u.Phone.Contains(input.SearchValue.Trim()))
                .WhereIF(Enum.IsDefined(typeof(StatusEnum), input.SearchStatus), (u, r,   sp, p) => u.Status == input.SearchStatus)
                .WhereIF(!superAdmin, (u, r,   sp, p) => u.AdminType != AdminType.SuperAdmin)
                .Select((u, r,   sp, p) => new { 
                    id= u.Id,
                    name= u.Name,
                    position=  p.Name,
                    type=   p.Floor,
                    birthday="未知",
                    mode=p.Remark,
                    roleId=r.SysRoleId,
                }).ToListAsync();


            roles.ForEach(x => x.items = users.Where(u => x.RoleId == u.roleId).ToList() ) ;

            return roles;
        }
        /// <summary>
        /// 增加用户       
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task AddUser(AddUserInput input)
        {
            var isExist = await _sysUserRep.AnyAsync(u => u.Account == input.Account);
            if (isExist) throw new ParamiterException(ErrorCode.D1003.GetEnumText());

            var user = input.Adapt<SysUser>();
            user.Password =Md5Crypt .Encrypt(input.Password);
            if (string.IsNullOrEmpty(user.Name))
                user.Name = user.Account;
            if (string.IsNullOrEmpty(user.NickName))
                user.NickName = user.Account;

            try
            {
                _sysUserRep.Ado.BeginTran();
                var newUser = await _sysUserRep.Context.Insertable(user).CallEntityMethod(m => m.Create()).ExecuteReturnEntityAsync();
                
                _sysUserRep.Ado.CommitTran();
            }
            catch (Exception)
            {
                _sysUserRep.Ado.RollbackTran();
                throw;
            }


        }

        /// <summary>
        /// 删除用户
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task DeleteUser(DeleteUserInput input)
        {
            var user = await _sysUserRep.FirstOrDefaultAsync(u => u.Id == input.Id);
            if (user.AdminType == AdminType.SuperAdmin)
                throw new ParamiterException(ErrorCode.D1014.GetEnumText());

            if (user.Account == _userManager.Account)
            {
                throw new ParamiterException(ErrorCode.D1001.GetEnumText());
            }
            try
            {
                _sysUserRep.Ado.BeginTran();
                // 直接删除用户
                await _sysUserRep.Context.Updateable(new SysUser {IsDeleted = true}).CallEntityMethod(m => m.Modify())
                    .UpdateColumns(user.FalseDeleteColumn()).Where(wh => wh.Id == user.Id).ExecuteCommandAsync();

                //删除该用户对应的用户-角色表关联信息
                await _sysUserRoleService.DeleteUserRoleListByUserId(user.Id);

                _sysUserRep.Ado.CommitTran();
            }
            catch (Exception)
            {
                _sysUserRep.Ado.RollbackTran();
                throw;
            }



        }

        /// <summary>
        /// 更新用户
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task UpdateUser(UpdateUserInput input)
        {
            // 排除自己并且判断与其他是否相同
            var isExist = await _sysUserRep.AnyAsync(u => u.Account == input.Account && u.Id != input.Id);
            if (isExist) throw new ParamiterException(ErrorCode.D1003.GetEnumText());

            var user = input.Adapt<SysUser>();

            try
            {
                _sysUserRep.Ado.BeginTran();
                await _sysUserRep.Context.Updateable<SysUser>(user).IgnoreColumns(it => new { it.Password, it.Status, it.AdminType }).IgnoreColumns(ignoreAllNullColumns: true).CallEntityMethod(m => m.Modify()).ExecuteCommandAsync();
        
                _sysUserRep.Ado.CommitTran();
            }
            catch (Exception)
            {
                _sysUserRep.Ado.RollbackTran();
                throw;
            }


        }

        /// <summary>
        /// 查看用户
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<dynamic> GetUser(QueryUserInput input)
        {
            var user = await _sysUserRep.FirstOrDefaultAsync(u => u.Id == input.Id);
            var userDto = user.Adapt<UserOutput>();
            return userDto;
        }

        /// <summary>
        /// 修改用户状态
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task ChangeUserStatus(UpdateUserInput input)
        {
            var user = await _sysUserRep.FirstOrDefaultAsync(u => u.Id == input.Id);
            if (user.AdminType == AdminType.SuperAdmin)
                throw new ParamiterException(ErrorCode.D1015.GetEnumText());

            if (!Enum.IsDefined(typeof(StatusEnum), input.Status))
                throw new ParamiterException(ErrorCode.D3005.GetEnumText());
            user.Status = input.Status;
            await _sysUserRep.Context.Updateable(user).CallEntityMethod(m => m.Modify()).ExecuteCommandAsync();
        }

        /// <summary>
        /// 授权用户角色
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task GrantUserRole(UpdateUserInput input)
        {
            await _sysUserRoleService.GrantRole(input);
        }

        /// <summary>
        /// 更新用户信息
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task UpdateUserInfo(UpdateUserInput input)
        {
            var user = input.Adapt<SysUser>();
            await _sysUserRep.Context.Updateable<SysUser>(user)
                .CallEntityMethod(m => m.Modify())
                .IgnoreColumns(ignoreAllNullColumns: true)
                .IgnoreColumns(it => new { it.AdminType, it.LastLoginTime })
                .ExecuteCommandAsync();
        }

        /// <summary>
        /// 修改用户密码
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task UpdateUserPwd(ChangePasswordUserInput input)
        {
            var user = await _sysUserRep.FirstOrDefaultAsync(u => u.Id == input.Id);
            if (Md5Crypt .Encrypt(input.Password) != user.Password)
                throw new ParamiterException(ErrorCode.D1004.GetEnumText());
            user.Password = Md5Crypt.Encrypt(input.NewPassword);
            await _sysUserRep.Context.Updateable<SysUser>(user).IgnoreColumns(ignoreAllNullColumns: true).CallEntityMethod(m => m.Modify()).ExecuteCommandAsync();
        }

        /// <summary>
        /// 获取用户拥有角色
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<dynamic> GetUserOwnRole(QueryUserInput input)
        {
            return await _sysUserRoleService.GetUserRoleIdList(input.Id);
        }

        /// <summary>
        /// 重置用户密码
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task ResetUserPwd(QueryUserInput input)
        {
            var user = await _sysUserRep.FirstOrDefaultAsync(u => u.Id == input.Id);
            user.Password = Md5Crypt.Encrypt("123456");
            await _sysUserRep.Context.Updateable(user).IgnoreColumns(it => new { it.AdminType }).IgnoreColumns(ignoreAllNullColumns: true).CallEntityMethod(m => m.Modify()).ExecuteCommandAsync();
        }

        /// <summary>
        /// 修改用户头像
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task UpdateAvatar(UploadAvatarInput input)
        {
            var user = await _sysUserRep.FirstOrDefaultAsync(u => u.Id == input.Id);
            user.Avatar = input.Avatar.ToString();
            await _sysUserRep.Context.Updateable<SysUser>(user).IgnoreColumns(it => new { it.AdminType }).IgnoreColumns(ignoreAllNullColumns: true).CallEntityMethod(m => m.Modify()).ExecuteCommandAsync();
        }

        /// <summary>
        /// 获取用户选择器
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<dynamic> GetUserSelector(UserInput input)
        {
            return await _sysUserRep.Context.Queryable<SysUser>()
                                   .WhereIF(!string.IsNullOrWhiteSpace(input.Name), u => (u.Name.Contains(input.Name.Trim())))
                                   .Where(u => u.IsDeleted ==false)
                                   .Where(u => u.AdminType != AdminType.SuperAdmin)
                                   .Select(u => new
                                   {
                                       u.Id,
                                       u.Name
                                   }).ToListAsync();
        }

        /// <summary>
        /// 根据用户Id获取用户
        /// </summary>
        /// <param name="userId"></param>
        /// <returns></returns>       
        public async Task<dynamic> GetUserById(long userId)
        {
            return await _sysUserRep.FirstOrDefaultAsync(u => u.Id == userId);
        }

        /// <summary>
        /// 将OAuth账号转换成账号
        /// </summary>
        /// <param name="authUser"></param>
        /// <param name="sysUser"></param>
        /// <returns></returns>
        public async Task SaveAuthUserToUser(AuthUserInput authUser, UserInput sysUser)
        {
            var user = sysUser.Adapt<SysUser>();
            user.AdminType = AdminType.None; // 非管理员

            // oauth账号与系统账号判断
            var isExist = await _sysUserRep.AnyAsync(u => u.Account == authUser.Username);
            user.Account = isExist ? authUser.Username + DateTime.Now.Ticks : authUser.Username;
            user.Name = user.NickName = authUser.Nickname;
            user.Email = authUser.Email;
            user.Sex = authUser.Gender;
            await _sysUserRep.Context.Insertable(user).CallEntityMethod(m => m.Create()).ExecuteCommandAsync();
        }
    }
}
